一、表單元件常用的屬性
二、按鈕元件:QBtn
三、文字輸入:QInput
四、核取方塊 (QCheckbox、QRadio)
五、下拉選單:(QSelect)
六、檔案選擇欄位:(QFile)
七、總結
disable
相當於原生HTML的disable
無法進行欄位的資料選取和修改
input-class的樣式也會稍微改變
readonly
可以選取資料,但是無法修改資料
不會改變input-class的樣式
v-model
元件呈現的資料綁定
範例示意:
<template>
    <div class="q-pa-md">
        <div class="q-gutter-y-md column" style="max-width: 300px">
          <q-input input-class="input rounded-borders" borderless v-model="text" hint="Readonly" :dense="dense" disable></q-input>
          <q-input input-class="input rounded-borders" borderless v-model="text" hint="Readonly" :dense="dense" readonly></q-input>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      text: '123'
    }
  }
}
</script>
<style lang="scss" scoped>
.input {
  padding: 0 7px;
  border: 1px solid #333;
}
</style>
用途相當廣泛的元件,經常用於
Quasar has a component called QBtn which is a button with a few extra useful features.
https://quasar.dev/vue-components/button#QBtn-API

<div class="q-pa-md q-gutter-sm">
    <q-btn unelevated type="a" href="start/pick-quasar-flavour" label="作為超連結" color="red-7"></q-btn>
</div>
<div class="q-pa-md q-gutter-sm">
    <q-btn unelevated :to="{ name: 'routeName' }" label="前端路由行為" color="green-7"></q-btn>
</div>
<div class="q-pa-md q-gutter-sm">
    <q-btn unelevated @click="someMethod" label="資料操作行為" color="blue-7"></q-btn>
</div>
QBtn的display是inline-block,預設寬度會根據內容改變
可以使用第二十一天談到的Flex Grid,設定寬度比例
以及第二十三天的class="full-width"設定與按鈕外的容器等寬

<div class="q-pa-md">
    <div class="row q-col-gutter-sm">
      <div class="col-12 col-sm-4">
        <q-btn class="full-width" unelevated type="a" href="start/pick-quasar-flavour" label="作為超連結" color="red-7"></q-btn>
      </div>
      
      <div class="col-12 col-sm-4">
        <q-btn class="full-width" unelevated label="前端路由行為" color="green-7"></q-btn>
      </div>
      
      <div class="col-12 col-sm-4">
        <q-btn class="full-width" unelevated @click="someMethod" label="資料操作行為" color="blue-7"></q-btn>
      </div>
    </div>
</div>
用於輸入文字的欄位
The QInput component is used to capture text input from the user. It uses v-model, similar to a regular input. It has support for errors and validation, and comes in a variety of styles, colors, and types.
https://quasar.dev/vue-components/input
除了一般的text,還包括了textarea和number
<div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-input
        outlined
        v-model="phone"
        label="phone"
      ></q-input>
      <q-input
        type="number"       
        outlined
        v-model="number"
        label="number"
      ></q-input>
      <q-input
        type="textarea"       
        outlined
        v-model="textarea"
        label="textarea"
      ></q-input>
    </div>
</div>
Quasar提供了很多預設的樣式
如果不喜歡的話,可以使用borderless屬性,另外使用class與input-class自訂樣式
https://quasar.dev/vue-components/input

<template>
    <div id="q-app">
      <div class="q-pa-md">
        <div class="q-gutter-y-md column" style="width: 300px; max-width: 100%">
          <q-toolbar class="q-pa-sm bg-primary text-white rounded-borders">
            <q-btn round dense flat icon="menu" class="q-mr-xs"></q-btn>
            <q-avatar class="gt-xs">
              <img src="https://cdn.quasar.dev/logo/svg/quasar-logo.svg">
            </q-avatar>
            <q-space></q-space>
            <q-input dense borderless v-model="text" class="text-input" class="q-ml-md">
              <template v-slot:append>
                <q-icon v-if="text === ''" name="search"></q-icon>
                <q-icon v-else name="clear" class="cursor-pointer" @click="text = ''"></q-icon>
              </template>
            </q-input>
          </q-toolbar>
        </div>
      </div>
    </div>
</template>
<script>
export default {
  data () {
    return {
      text: ''
    }
  }
}
</script>
<style lang="scss" scoped>
.text-input {
  margin: 3px 12px;
  padding: 5px;
  background: white;
  border-radius: 10px;
}
</style>
QInput 前後可以透過<template v-slot:append>加入ICON

 <q-input outlined bottom-slots v-model="text" label="Label" counter :dense="dense">
        <template v-slot:prepend>
          <q-icon name="place" />
        </template>
        <template v-slot:append>
          <q-icon name="close" @click="text = ''" class="cursor-pointer" />
        </template>
 </q-input>
「clear屬性」自帶清除內容的功能

<q-input
    clearable
    clear-icon="close"
    outlined
    v-model="text"
    label="Label"
/>
「mask屬性」可以用於特定格式的文字輸入
<div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-input
        outlined
        v-model="phone"
        label="phone"
        mask="####-### ###"
        fill-mask="#"
      ></q-input>
    </div>
</div>
搭配QForm,可以做簡單的格式校驗
https://quasar.dev/vue-components/form

<template>
  <div class="q-pa-md" style="max-width: 400px">
    <q-form
      @submit="onSubmit"
      @reset="onReset"
      class="q-gutter-md"
    >
      <q-input
        filled
        v-model="name"
        label="Your name *"
        hint="Name and surname"
        lazy-rules
        :rules="[ val => val && val.length > 0 || 'Please type something']"
      />
      <q-input
        filled
        type="number"
        v-model="age"
        label="Your age *"
        lazy-rules
        :rules="[
          val => val !== null && val !== '' || 'Please type your age',
          val => val > 0 && val < 100 || 'Please type a real age'
        ]"
      />
      <q-toggle v-model="accept" label="I accept the license and terms" />
      <div>
        <q-btn label="Submit" type="submit" color="primary"/>
        <q-btn label="Reset" type="reset" color="primary" flat class="q-ml-sm" />
      </div>
    </q-form>
  </div>
</template>
<script>
export default {
  data () {
    return {
      name: null,
      age: null,
      accept: false
    }
  },
  methods: {
    onSubmit () {
      if (this.accept !== true) {
        this.$q.notify({
          color: 'red-5',
          textColor: 'white',
          icon: 'warning',
          message: 'You need to accept the license and terms first'
        })
      }
      else {
        this.$q.notify({
          color: 'green-4',
          textColor: 'white',
          icon: 'cloud_done',
          message: 'Submitted'
        })
      }
    },
    onReset () {
      this.name = null
      this.age = null
      this.accept = false
    }
  }
}
</script>
常用於某組資料的多選
或者類似加入會員的同意條款選項
The QCheckbox component is another basic element for user input. You can use this to supply a way for the user to toggle an option.
https://quasar.dev/vue-components/checkbox
多選的v-model要指向同一個data陣列變數
<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm">
      <q-checkbox v-model="selection" val="teal" label="Teal" color="teal" />
      <q-checkbox v-model="selection" val="orange" label="Orange" color="orange" />
      <q-checkbox v-model="selection" val="red" label="Red" color="red" />
      <q-checkbox v-model="selection" val="cyan" label="Cyan" color="cyan" />
    </div>
    <div class="q-px-sm">
      The model data: <strong>{{ selection }}</strong>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      selection: [ 'teal', 'red' ]
    }
  }
}
</script>
單一選項的勾選狀態,data變數的值為true或false

<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm">
      <q-checkbox
        v-model="customModel"
        color="secondary"
        label="Do you agree with the terms & conditions?"
      ></q-checkbox>
    </div>
    <div class="q-px-sm">
      The model data: <strong>'{{ customModel }}'</strong>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      customModel: false
    }
  }
}
</script>
相對於Checkbox,用於某組資料的單選
The QRadio component is another basic element for user input. You can use this to supply a way for the user to pick an option from multiple choices.
v-model要指向同一個data變數
<template>
  <div class="q-pa-md">
    <div class="q-gutter-sm">
      <q-radio v-model="color" val="teal" label="Teal" color="teal" />
      <q-radio v-model="color" val="orange" label="Orange" color="orange" />
      <q-radio v-model="color" val="red" label="Red" color="red" />
      <q-radio v-model="color" val="cyan" label="Cyan" color="cyan" />
    </div>
    <div class="q-gutter-sm">
      <q-radio keep-color v-model="color" val="teal" label="Teal" color="teal" />
      <q-radio keep-color v-model="color" val="orange" label="Orange" color="orange" />
      <q-radio keep-color v-model="color" val="red" label="Red" color="red" />
      <q-radio keep-color v-model="color" val="cyan" label="Cyan" color="cyan" />
    </div>
    <div class="q-px-sm q-mt-sm">
      Your selection is: <strong>{{ color }}</strong>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      color: 'cyan'
    }
  }
}
</script>
具有強大篩選功能的單選或下拉選單
The QSelect component has two types of selection: single or multiple. This component opens up a menu for the selection list and action. A filter can also be used for longer lists.
https://quasar.dev/vue-components/select
其中QSelect的選單選項格式允許:
<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>
      <q-select filled v-model="model" :options="options" label="Standard" />
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      model: null,
      options: [
        'Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'
      ]
    }
  }
}
</script>
<template>
  <div class="q-pa-md" style="max-width: 300px">
    <div class="q-gutter-md">
      <q-badge color="secondary" multi-line>
        Model: "{{ model }}"
      </q-badge>
      <q-select filled v-model="model" :options="options" label="Standard" />
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      model: null,
      options: [
        {
          label: 'Google',
          value: 'Google',
          description: 'Search engine',
          category: '1'
        },
        {
          label: 'Facebook',
          value: 'Facebook',
          description: 'Social media',
          category: '1'
        },
        {
          label: 'Twitter',
          value: 'Twitter',
          description: 'Quick updates',
          category: '2'
        },
        {
          label: 'Apple',
          value: 'Apple',
          description: 'iStuff',
          category: '2'
        },
        {
          label: 'Oracle',
          value: 'Oracle',
          disable: true,
          description: 'Databases',
          category: '3'
        }
      ]
    }
  }
}
</script>
要注意的是
如果選項是JSON格式
至少要包含「label」和「value」
label是顯示在QSelect上面的文字,value是代表這個選項的值
此時v-model預設的格式,會是整個選項的JSON格式

{ label: 'Test', value: 0  }
如果你希望v-model的格式,是JSON選項的value,在QSelect顯示label
使用emit-value + map-options 屬性

<q-select
    filled
    v-model="model"
    :options="options"
    label="Standard"
    emit-value
    map-options
/>
若要使用QSelect的篩選功能
需要設定「@filter」、「use-input」、「hide-selected」

<template>
  <div class="q-pa-md">
    <div class="q-gutter-md row">
      <q-select
        filled
        v-model="model"
        use-input
        hide-selected
        fill-input
        input-debounce="0"
        :options="options"
        @filter="filterFn"
        hint="Basic filtering"
        style="width: 250px; padding-bottom: 32px"
      >
        <template v-slot:no-option>
          <q-item>
            <q-item-section class="text-grey">
              No results
            </q-item-section>
          </q-item>
        </template>
      </q-select>
    </div>
  </div>
</template>
<script>
const stringOptions = [
  'Google', 'Facebook', 'Twitter', 'Apple', 'Oracle'
]
export default {
  data () {
    return {
      model: null,
      options: stringOptions
    }
  },
  methods: {
    filterFn (val, update, abort) {
      update(() => {
        const needle = val.toLowerCase()
        this.options = stringOptions.filter(v => v.toLowerCase().indexOf(needle) > -1)
      })
    }
  }
}
</script>
有寫過檔案上傳的人應該知道
\原生的type=file,是不能使用v-model
QInput也是,不能使用v-model
Do NOT use a v-model when QInput is of type="file". Browser security policy does not allow a value to be set to such an input. As a result, you can only read it (attach an @input event), but not write it.
https://quasar.dev/vue-components/input

<template>
  <q-page class="flex flex-center q-gutter-md">
    <div>
      <q-input type="file" @change="selectData" borderless></q-input>
      <q-img :src="dataUri" v-show="dataUri !== null" width="300px"></q-img>
    </div>
  </q-page>
</template>
<script>
export default {
  name: 'PageIndex',
  
  data () {
    return {
      file: null,
      dataUri: null
    }
  },
  methods: {
    selectData (e) {
      const reader = new FileReader()
      this.file = e.target.files[0]
      reader.readAsDataURL(this.file)
      reader.onload = (e) => {
        this.dataUri = e.target.result
      }
    }
  }
}
</script>
你可使用QFile代替
QFile本身包含了@change => data 這段過程
QFile is a component which handles the user interaction for picking file(s).
https://quasar.dev/vue-components/file-picker

<template>
  <q-page class="flex flex-center q-gutter-md">
    <div style="width: 300px;">
      <q-file stack-label="選擇檔案" label-color="white" input-class="text-white" class="bg-grey-9 q-pa-sm" borderless v-model="file" @input="selectData"></q-file>
      <q-img :src="dataUri" v-show="dataUri !== null" width="300px"></q-img>
    </div>
  </q-page>
</template>
<script>
export default {
  name: 'PageIndex',
  
  data () {
    return {
      file: null,
      dataUri: null
    }
  },
  methods: {
    selectData (file) {
      const reader = new FileReader()
      this.file = file
      reader.readAsDataURL(this.file)
      reader.onload = (e) => {
        this.dataUri = e.target.result
      }
    }
  }
}
</script>
今天大致介紹了比較常用表單元件
如果對其他的元件有興趣,可以參考Quasar的官方元件
明天接著介紹經常與表單搭配使用的Dialog